﻿using Tesla.Bounding;
using Tesla.Core;
using Tesla.Graphics;
using Tesla.Math;
using Tesla.Scene;
using Tesla.Scene.Extension;
using Tesla.Scene.Shape;

namespace TeslaSamples.Effects {
    [AppDescription("Planet Sample", PlatformCapabilities.Direct3D10, "PlanetImage", "PlanetDesc", "PlanetSource")]
    public class PlanetSample : BasicApp {

        private Material material;

        protected override void LoadContent() {
            Window.Title = "Planet Sample";
            Renderer.CurrentCamera.Position = new Vector3(0, 0, 750);

            Sphere planet = new Sphere("Earth", 100, 100, 200);
            planet.Material = ContentManager.Load<Material>("Materials//PlanetMaterial.tem");

            planet.Material.AddLogic(new PlanetLogic());
            planet.Rotation = Quaternion.FromAngleAxis(MathHelper.ToRadians(-90.0f), Vector3.UnitX);
            planet.SceneHints.RenderBucketType = RenderBucketType.Transparent;
            planet.ComputeTangentBasis();
            planet.SetModelBound(new BoundingSphere());
            material = planet.Material;

            Node orbit = new Node("Orbit");
            orbit.AddChild(planet);
            orbit.AddController(new RotateController(Vector3.UnitY, .75f));
            RootNode.AddChild(orbit);
            orbit.Rotation = Quaternion.FromAngleAxis(MathHelper.DegreesToRadians * 45, Vector3.UnitY);

            DirectionalLight dl = new DirectionalLight();
            dl.Direction = new Vector3(-.755f, -.755f, -.755f);
            planet.AddLight(dl);

            //TODO: The planet only renders properly if it's centered at the origin
            //orbit.Translation = new Vector3(0, -500, 0);
            Box sky = new Box("Space", Vector3.Zero, 100, 100, 100);
            sky.SceneHints.RenderBucketType = RenderBucketType.PreBucket;
            sky.Material = ContentManager.Load<Material>("Materials//SpaceSkybox.tem");

            RootNode.AddChild(sky);
        }

        protected override void Update(GameTime time) {
            base.Update(time);
            material.SetParameter("Time", false, (float) time.TotalGameTime.TotalSeconds);
        }
    }

    public class PlanetLogic : BaseMaterialLogic {


        public PlanetLogic()
            : base("PlanetLogic") {
        }

        public override IMaterialLogic Clone() {
            return new PlanetLogic();
        }

        public override void Execute(Material material, IRenderer renderer, IRenderable mesh) {
            if(IsEnabled) {
                Vector3 v =renderer.CurrentCamera.Position;
                material.SetParameter("CamHeight", false, v.Length());
                material.SetParameter("CamHeightSquared", false, v.LengthSquared());
                //material.SetParameter("Time", false, (float) timer.GameTime.TotalGameTime.TotalSeconds); //Have some app-level access to the timing mechanism?
            }
        }
    }
}
